# -*- coding: utf-8 -*-
"""
Created on Thu Sep 23 23:52:53 2021

未使用特征变化得到的结果

@author: 刘长奇-2019300677
"""


import pandas as pd
data = pd.read_csv ("dataset_circles.csv")
import numpy as np
import matplotlib.pyplot as plt
import random
data = np.array (data)
num = np.shape (data) [0]
x0 = []
x1 = []
#样本数据的两个维度

y=[]
#样本数据的类别

#数据归一化处理，进行特征变化
def one (num,jz1):
    max1=np.max(jz1)
    
    min1=np.min(jz1)
    
    return (num-min1)/(max1-min1)

#整合数据：

for i in range(num) :
    x0.append(data[i,0])
    x1.append(data[i, 1])
    y.append(data[i,2])
x0 = np.array(x0)
x1 = np.array(x1)
y = np.array (y)
x = np.hstack((x0. reshape(-1,1) ,x1. reshape(-1, 1)))
y = y.reshape(-1, 1)

#画出没有特征变化的图：
plt.figure()
plt.scatter(x[:,0],x[:,1],c = y)
plt.title('without feature change')

#画出经过特征变化的图：
for i in range(num) :
    x0[i]=one(x0[i],x0)
    x1[i]=one(x1[i],x1)
x = np.hstack((x0. reshape(-1,1) ,x1. reshape(-1, 1)))
y = y.reshape(-1, 1)

plt.figure()
plt.scatter(x[:,0],x[:,1],c = y)
plt.title('with feature change')
plt.colorbar
plt.show ()


#kmeans
def calc_distance(v1, v2):
    return np.sum(np.square(v1-v2))

def rand_cluster_cents(X, k):
    """初始化聚类中心：通过在区间范围随机产生的值作为新的中心点"""

    # 样本数
    m=np.shape(X)[0]
    
    # 生成随机下标列表
    dataIndex=list(range(m))
    random.shuffle(dataIndex)
    centroidsIndex = dataIndex[:k]
    
    # 返回随机的聚类中心
    return X[centroidsIndex, :]

def kmeans(X, k):
    # 样本总数
    m = np.shape(X)[0]
    # 分配样本到最近的簇：存[簇序号,距离的平方] (m行 x 2 列)
    clusterAssment = np.zeros((m, 2))

    # step1: 通过随机产生的样本点初始化聚类中心
    centroids = rand_cluster_cents(X, k)
    print('最初的中心=', centroids)

    # 初始化迭代次数计数器
    iterN = 0
    
    # 所有样本分配结果不再改变，迭代终止
    while True:   
        # 标志位，如果迭代前后样本分类发生变化值为True，否则为False
        clusterChanged = False
    
        # step2:分配到最近的聚类中心对应的簇中
        for i in range(m):
            # 初始定义距离为无穷大
            minDist = np.inf;
            # 初始化索引值
            minIndex = -1
            # 计算每个样本与k个中心点距离
            for j in range(k):
                # 计算第i个样本到第j个中心点的距离
                distJI = calc_distance(centroids[j, :], X[i, :])
                # 判断距离是否为最小
                if distJI < minDist:
                    # 更新获取到最小距离
                    minDist = distJI
                    # 获取对应的簇序号
                    minIndex = j
            # 样本上次分配结果跟本次不一样，标志位clusterChanged置True
            if clusterAssment[i, 0] != minIndex:
                clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist ** 2  # 分配样本到最近的簇
            
        iterN += 1
        sse = sum(clusterAssment[:, 1])
        print('the SSE of %d' % iterN + 'th iteration is %f' % sse)
        
        # step3:更新聚类中心
        for cent in range(k):  # 样本分配结束后，重新计算聚类中心
            # 获取该簇所有的样本点,nonzero[0]表示A == cent的元素所在的行，如果没有[0],列也会表示
            ptsInClust = X[clusterAssment[:, 0] == cent, :]
            # 更新聚类中心：axis=0沿列方向求均值。
            centroids[cent, :] = np.mean(ptsInClust, axis=0)
        
        # 如果聚类重心没有发生改变，则退出迭代
        if not clusterChanged:
            break
            
    return centroids, clusterAssment
# 进行k-means聚类
k = 2  # 用户定义聚类数
mycentroids, clusterAssment = kmeans(x, k)
def datashow(dataSet, k, centroids, clusterAssment):  # 二维空间显示聚类结果
    from matplotlib import pyplot as plt
    num, dim = np.shape(dataSet)  # 样本数num ,维数dim

    if dim != 2:
        print('sorry,the dimension of your dataset is not 2!')
        return 1
    marksamples = ['ob', 'or', 'og', 'ok', '^r', '^b', '<g']  # 样本图形标记
    if k > len(marksamples):
        print('sorry,your k is too large,please add length of the marksample!')
        return 1
        # 绘所有样本
    for i in range(num):
        markindex = int(clusterAssment[i, 0])  # 矩阵形式转为int值, 簇序号
        # 特征维对应坐标轴x,y；样本图形标记及大小
        plt.plot(dataSet[i, 0], dataSet[i, 1], marksamples[markindex], markersize=6)

    # 绘中心点
    markcentroids = ['o', '*', '^','8']  # 聚类中心图形标记
    label = ['0', '1', '2','3']
    c = ['green', 'pink', 'red','black']
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], markcentroids[i], markersize=15, label=label[i], c=c[i])
        plt.legend(loc='upper left')  #图例
    plt.xlabel('feature 1')
    plt.ylabel('feature 2')

    plt.title('k-means cluster result')  # 标题
    plt.show()
    
    
# 画出实际图像
def trgartshow(dataSet, k, labels):
    from matplotlib import pyplot as plt

    num, dim = np.shape(dataSet)
    #label = ['0', '1', '2']
    marksamples = ['ob', 'or', 'og', 'ok', '^r', '^b', '<g']
    # 通过循环的方式，完成分组散点图的绘制
    for i in range(num):
        plt.plot(dataSet[i, 0], dataSet[i, 1], marksamples[int(labels[i])], markersize=6)

    
    # 添加轴标签和标题
    plt.xlabel('feature 1')
    plt.ylabel('feature 2')
    plt.title('true result')  # 标题

    # 显示图形
    plt.show()
    # label=labels.iat[i,0]
# 绘图显示
datashow(x, k, mycentroids, clusterAssment)
trgartshow(x, 2, y)